package com.turbo.cloud.gateway.filter.auth;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.turbo.cloud.gateway.config.AuthProperties;
import com.turbo.cloud.gateway.constant.GatewayConstants;
import com.turbo.cloud.gateway.utils.RedisUtil;
import com.turbo.cloud.gateway.utils.caffeine.CaffeineCacheUtil;
import com.turbo.cloud.gateway.utils.PathUtil;
import com.turbo.cloud.gateway.utils.jwt.AdminUser;
import com.turbo.cloud.gateway.utils.jwt.JwtPayload;
import com.turbo.cloud.gateway.utils.jwt.JwtProperties;
import com.turbo.cloud.gateway.utils.jwt.JwtUtils;
import com.turbo.cloud.gateway.web.client.UmsReactiveWebService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;


/**
 * 接口地址权限验证
 *
 * @author zhangluning
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class ApiAuthLogic {

    final UmsReactiveWebService umsReactiveWebService;
    final JwtProperties jwtProperties;
    final AuthProperties authProperties;
    final RedisUtil redisUtil;

    /**
     * 验证Interface段接口秘钥
     *
     * @param request 请求
     */
    public boolean validatePermission(ServerHttpRequest request) {
        if (!authProperties.getApiAuth().getEnabled()) {
            return true;
        }

        String path = request.getPath().value();
        if (PathUtil.isOpenApi(path)) {
            return true;
        }

        String tokenHead = jwtProperties.getTokenHead();
        String secret = jwtProperties.getSecret();

        String authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isBlank(authorization) || !authorization.startsWith(tokenHead)) {
            return true;
        } else {
            // The part after "Bearer " 有个空格
            String authToken = authorization.substring(tokenHead.length());
            JwtPayload<AdminUser> jwtPayload = JwtUtils.getUserInfoFromToken(authToken, secret, AdminUser.class);
            AdminUser adminUser = jwtPayload.getUserInfo();

            if (Objects.isNull(adminUser) || CollectionUtils.isEmpty(adminUser.getPermissionIds())) {
                return false;
            }

            String cacheKey = GatewayConstants.REDIS_KEY_API_PERMISSION_PREFIX + path;
            // 缓存5分钟有效期
            List<String> cacheApiPermissionsList = CaffeineCacheUtil.getApiCache(cacheKey);
            if (CollectionUtils.isEmpty(cacheApiPermissionsList)) {
                String permissionIdsJson = redisUtil.get(cacheKey);
                if (StrUtil.isNotBlank(permissionIdsJson)) {
                    cacheApiPermissionsList = JSON.parseArray(permissionIdsJson, String.class);
                    // 防止缓存穿透
                    if (CollectionUtils.isEmpty(cacheApiPermissionsList)) {
                        cacheApiPermissionsList = new ArrayList<>();
                    }
                    CaffeineCacheUtil.setApiCache(cacheKey, cacheApiPermissionsList);
                }
            }
            return hasPermission(cacheApiPermissionsList, adminUser.getPermissionIds());
        }
    }

    /**
     * 是否有权限
     *
     * @param cacheApiPermissionsList 缓存的接口权限ID集合
     * @param userPermissionList      用户的接口权限ID集合
     * @return 是否有效
     */
    private boolean hasPermission(List<String> cacheApiPermissionsList, List<String> userPermissionList) {
        if (CollectionUtils.isEmpty(cacheApiPermissionsList) || CollectionUtils.isEmpty(userPermissionList)) {
            return false;
        }

        for (String userRoleId : userPermissionList) {
            if (cacheApiPermissionsList.contains(userRoleId)) {
                return true;
            }
        }
        return false;
    }
}
